home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 501-525 / disk_512 / csh / csh515s.lzh / sub.c < prev    next >
C/C++ Source or Header  |  1991-06-12  |  21KB  |  1,118 lines

  1.  
  2. /*
  3.  * SUB.C
  4.  *
  5.  * (c)1986 Matthew Dillon     9 October 1986
  6.  *
  7.  * Version 2.07M by Steve Drew 10-Sep-87
  8.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  9.  * Version 5.00L by Urban Mueller 17-Feb-91
  10.  *
  11.  */
  12.  
  13. #include "shell.h"
  14. #include "proto.h"
  15.  
  16. static void del_history( void );
  17. static int dnext( struct DPTR *dp, char **pname, int *stat);
  18. static char *svfile( char *s1, char *s2, FIB *fib);
  19. static int exall( BPTR lock, char *path );
  20. static void quicksort( char **av, int n );
  21.  
  22.  
  23. #define HM_STR 0              /* various HISTORY retrieval modes */
  24. #define HM_REL 1
  25. #define HM_ABS 2
  26.  
  27. void
  28. seterr( int err )
  29. {
  30.     static int LastErr;
  31.     char buf[32], *val;
  32.     int  stat=0;
  33.  
  34.     Lastresult=err;
  35.  
  36.     if( LastErr!=err ) {
  37.         LastErr=err;
  38.         sprintf(buf, "%d", err);
  39.         set_var(LEVEL_SET, v_lasterr, buf);
  40.  
  41.         if( val=get_var(LEVEL_SET, v_stat))
  42.             stat = atoi(val);
  43.         if (stat < Lastresult) set_var(LEVEL_SET, v_stat, buf);
  44.     }
  45. }
  46.  
  47. char *
  48. next_word( char *str )
  49. {
  50.     while (*str && ! ISSPACE(*str)) ++str;
  51.     while (*str &&   ISSPACE(*str)) ++str;
  52.     return str;
  53. }
  54.  
  55. /*
  56.  * FREE(ptr)   --frees without actually freeing, so the data is still good
  57.  *               immediately after the free.
  58.  */
  59.  
  60.  
  61. void
  62. Free( void *ptr )
  63. {
  64.     static char *old_ptr;
  65.  
  66.     if (old_ptr) free (old_ptr);
  67.     old_ptr = ptr;
  68. }
  69.  
  70. /*
  71.  * Add new string to history (H_head, H_tail, H_len,
  72.  *  S_histlen
  73.  */
  74.  
  75. void
  76. add_history( char *str )
  77. {
  78.     struct HIST *hist;
  79.     char *get;
  80.  
  81.     for( get=str; *get; get++ )
  82.         if( (*get&127)<' ')
  83.             *get=' ';
  84.  
  85.     if (H_head != NULL && !strcmp(H_head->line, str))
  86.         return;
  87.     while (H_len > S_histlen)
  88.         del_history();
  89.     hist = (struct HIST *)salloc (sizeof(struct HIST));
  90.     if (H_head == NULL) {
  91.         H_head = H_tail = hist;
  92.         hist->next = NULL;
  93.     } else {
  94.         hist->next = H_head;
  95.         H_head->prev = hist;
  96.         H_head = hist;
  97.     }
  98.     hist->prev = NULL;
  99.     hist->line = salloc (strlen(str) + 1);
  100.     strcpy (hist->line, str);
  101.     ++H_len;
  102. }
  103.  
  104. static void
  105. del_history()
  106. {
  107.     if (H_tail) {
  108.         --H_len;
  109.         ++H_tail_base;
  110.         free (H_tail->line);
  111.         if (H_tail->prev) {
  112.             H_tail = H_tail->prev;
  113.             free (H_tail->next);
  114.         H_tail->next = NULL;
  115.         } else {
  116.             free (H_tail);
  117.             H_tail = H_head = NULL;
  118.         }
  119.     }
  120. }
  121.  
  122. char *
  123. get_history( char *ptr, int echo, int occur )
  124. {
  125.     struct HIST *hist;
  126.     int len;
  127.     int mode = HM_REL;
  128.     int num  = 1, found=0;
  129.     char *str=NULL;
  130.     char *result = NULL;
  131.  
  132.     if (ptr[1] >= '0' && ptr[1] <= '9') {
  133.         mode = HM_ABS;
  134.         num  = atoi(&ptr[1]);
  135.         goto skip;
  136.     }
  137.     switch (ptr[1]) {
  138.     case '!':
  139.         break;
  140.     case '-':
  141.         num += atoi(&ptr[2]);
  142.         break;
  143.     default:
  144.         mode = HM_STR;
  145.         str  = ptr + 1;
  146.         break;
  147.     }
  148. skip:
  149.     switch (mode) {
  150.     case HM_STR:
  151.         len = strlen(str);
  152.         for (hist = H_head; hist; hist = hist->next) {
  153.             if (Strncmp(hist->line, str, len) == 0 && *hist->line != '!') {
  154.                 result = hist->line;
  155.                 if( !occur || ++found==occur )
  156.                     break;
  157.             }
  158.         }
  159.         break;
  160.     case HM_REL:
  161.         for (hist = H_head; hist && num--; hist = hist->next);
  162.         if (hist)
  163.         result = hist->line;
  164.         break;
  165.     case HM_ABS:
  166.         len = H_tail_base;
  167.         for (hist = H_tail; hist && len != num; hist = hist->prev, ++len);
  168.         if (hist)
  169.         result = hist->line;
  170.         break;
  171.     }
  172.     if( echo==1 )
  173.         fprintf(stderr, result ? "%s\n" : "History failed\n", result);
  174.     if( !result ) 
  175.         if( echo==2 )
  176.             DisplayBeep(NULL);
  177.         else 
  178.             result="";
  179.     return result;
  180. }
  181.  
  182. void
  183. replace_head( char *str )
  184. {
  185.     if (str && strlen(str) && H_head) {
  186.         free (H_head->line);
  187.         H_head->line = salloc (strlen(str)+1);
  188.         strcpy (H_head->line, str);
  189.     }
  190. }
  191.  
  192.  
  193. #if 0
  194. #define CDLEN 20
  195. static int   cd_len=CDLEN, cd_read, cd_write, cd_current;
  196. static char *cd_hist[CDLEN];
  197.  
  198. add_cdhist( char *str )
  199. {
  200.     if( !str )
  201.         return;
  202.     if( cd_hist[cd_write] )
  203.         free(cd_hist[cd_write]);
  204.     cd_hist[cd_write++]=str;
  205.     cd_write%=cd_len;
  206.     cd_current=cd_write;
  207. }
  208.  
  209. char *
  210. back_cdhist( void )
  211. {
  212.     if( cd_current!=cd_write ) cd_current= --cd_current % cd_len;
  213.     return cd_hist[cd_current];
  214. }
  215.  
  216. char *
  217. forw_cdhist( void )
  218. {
  219.     if( cd_current!=cd_read  ) cd_current= ++cd_current % cd_len;
  220.     return cd_hist[cd_current];
  221. }
  222. #endif
  223.  
  224. void
  225. pError(char *str )
  226. {
  227.     int ierr = (long)IoErr();
  228.     ierror(str, ierr);
  229. }
  230.  
  231. ierror( char *str, int err )
  232. {
  233.     struct PERROR *per = Perror;
  234.  
  235.     setioerror(err);
  236.  
  237.     if (err) {
  238.         for (; per->errstr; ++per) {
  239.             if (per->errnum == err) {
  240.                 fprintf (stderr, "%s%s%s\n",
  241.                 per->errstr,
  242.                 (str) ? ": " : "",
  243.                 (str) ? str : "");
  244.                 return err;
  245.             }
  246.         }
  247.         fprintf (stderr, "Unknown DOS error %d: %s\n", err, (str) ? str : "");
  248.     }
  249.     return err;
  250. }
  251.  
  252. void
  253. setioerror( int err )
  254. {
  255.     static int LastIoError=-1;
  256.     char buf[20];
  257.  
  258.     IoError=err;
  259.     if( IoError<0 ) IoError=0;
  260.     if( LastIoError!=IoError) {
  261.         LastIoError=IoError;
  262.         sprintf(buf, "%d", IoError);
  263.         set_var(LEVEL_SET, v_ioerr, buf);
  264.     }
  265. }
  266.  
  267. char *
  268. ioerror(int num)
  269. {
  270.     struct PERROR *per = Perror;
  271.  
  272.     for ( ; per->errstr; ++per)
  273.         if (per->errnum == num)
  274.             return per->errstr;
  275.     return NULL;
  276. }
  277.  
  278. /*
  279.  * Disk directory routines
  280.  *
  281.  * dptr = dopen(name, stat)
  282.  *    struct DPTR *dptr;
  283.  *    char *name;
  284.  *    int *stat;
  285.  *
  286.  * dnext(dptr, name, stat)
  287.  *    struct DPTR *dptr;
  288.  *    char **name;
  289.  *    int  *stat;
  290.  *
  291.  * dclose(dptr)                  -may be called with NULL without harm
  292.  *
  293.  * dopen() returns a struct DPTR, or NULL if the given file does not
  294.  * exist.  stat will be set to 1 if the file is a directory.  If the
  295.  * name is "", then the current directory is openned.
  296.  *
  297.  * dnext() returns 1 until there are no more entries.  The **name and
  298.  * *stat are set.  *stat != 0 if the file is a directory.
  299.  *
  300.  * dclose() closes a directory channel.
  301.  *
  302.  */
  303.  
  304. struct DPTR *
  305. dopen( char *name, int *stat)
  306. {
  307.     struct DPTR *dp;
  308.  
  309.     IoError=0;
  310.     *stat = 0;
  311.     dp = (struct DPTR *)salloc(sizeof(struct DPTR));
  312.     if (*name == '\0')
  313.         dp->lock = DupLock(Myprocess->pr_CurrentDir);
  314.     else
  315.         dp->lock = Lock (name,ACCESS_READ);
  316.     if (dp->lock == NULL) {
  317.         IoError=IoErr();
  318.         free (dp);
  319.         return NULL;
  320.     }
  321.     dp->fib = (FIB *)SAllocMem((long)sizeof(FIB), MEMF_PUBLIC);
  322.     if (!Examine (dp->lock, dp->fib)) {
  323.         pError (name);
  324.         dclose (dp);
  325.         return NULL;
  326.     }
  327.     if (dp->fib->fib_DirEntryType >= 0) *stat = 1;
  328.     return dp;
  329. }
  330.  
  331. static int
  332. dnext( struct DPTR *dp, char **pname, int *stat)
  333. {
  334.     if (dp == NULL) return (0);
  335.  
  336.     if (ExNext (dp->lock, dp->fib)) {
  337.         *stat = 0;
  338.         if( dp->fib->fib_DirEntryType >= 0)
  339.             *stat= dp->fib->fib_DirEntryType!=ST_USERDIR ? 2 : 1;
  340.         *pname = dp->fib->fib_FileName;
  341.         return 1;
  342.     }
  343.     return 0;
  344. }
  345.  
  346. int
  347. dclose( struct DPTR *dp )
  348. {
  349.     if (dp == NULL)
  350.         return 1;
  351.     if (dp->fib)
  352.         FreeMem (dp->fib,(long)sizeof(*dp->fib));
  353.     if (dp->lock)
  354.         UnLock (dp->lock);
  355.     free (dp);
  356.     return 1;
  357. }
  358.  
  359.  
  360. int
  361. isdir( char *file )
  362. {
  363.     struct DPTR *dp;
  364.     int stat;
  365.  
  366.     stat = 0;
  367.     if (dp = dopen (file, &stat))
  368.         dclose(dp);
  369.     return (stat!=0);
  370. }
  371.  
  372.  
  373. void
  374. free_expand( char **av )
  375. {
  376.     char **get = av;
  377.  
  378.     if (av) {
  379.         while (*get)
  380.         free (*get++-sizeof(struct file_info));
  381.         free (av);
  382.     }
  383. }
  384.  
  385. /*
  386.  * EXPAND(base,pac)
  387.  *    base           - char * (example: "df0:*.c")
  388.  *    pac            - int  *  will be set to # of arguments.
  389.  *
  390.  * 22-May-87 SJD.  Heavily modified to allow recursive wild carding and
  391.  *                 simple directory/file lookups. Returns a pointer to
  392.  *                 an array of pointers that contains the full file spec
  393.  *                 eg. 'df0:c/sear*' would result in : 'df0:C/Search'
  394.  *
  395.  *                 Now no longer necessary to Examine the files a second time
  396.  *                 in do_dir since expand will return the full file info
  397.  *                 appended to the file name. Set by formatfile().
  398.  *                 eg. fullfilename'\0'rwed  NNNNNN NNNN  DD-MMM-YY HH:MM:SS
  399.  *
  400.  *                 Caller must call free_expand when done with the array.
  401.  *
  402.  * base             bname =       ename =
  403.  * ------           -------       -------
  404.  *  "*"               ""            "*"
  405.  *  "!*.info"         ""            "*.info" (wild_exclude set)
  406.  *  "su*d/*"          ""            "*"      (tail set)
  407.  *  "file.*"          ""            "file.*"
  408.  *  "df0:c/*"         "df0:c"       "*"
  409.  *  ""                ""            "*"
  410.  *  "df0:.../*"       "df0:"        "*"      (recur set)
  411.  *  "df0:sub/.../*"   "df0:sub"     "*"      (recur set)
  412.  *
  413.  * ---the above base would be provided by execom.c or do_dir().
  414.  * ---the below base would only be called from do_dir().
  415.  *
  416.  *  "file.c"          "file.c"      ""       if (dp == 0) fail else get file.c
  417.  *  "df0:"            "df0:"        "*"
  418.  *  "file/file"       "file/file"   ""       (dp == 0) so fail
  419.  *  "df0:.../"        "df0:"        "*"      (recur set)
  420.  *
  421.  */
  422.  
  423. char **
  424. expand( char *base, int *pac )
  425. {
  426.     char *ptr;
  427.     char **eav = (char **)salloc(sizeof(char *) * (2));
  428.     short eleft, eac;
  429.     char *name;
  430.     char *bname, *ename, *tail;
  431.     int stat, recur, scr, bl;
  432.     struct DPTR *dp;
  433.  
  434.     IoError = *pac = recur = eleft = eac = 0;
  435.  
  436.     base = strcpy(malloc(strlen(base)+1), base);
  437.     for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);
  438.  
  439.     if (!*ptr)   /* no wild cards */
  440.         --ptr;
  441.     else
  442.         for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);
  443.  
  444.     if (ptr < base) {
  445.         bname = strcpy (malloc(1), "");
  446.     } else {
  447.         scr = ptr[1];
  448.         ptr[1] = '\0';
  449.         if (!strcmp(ptr-3,".../")) {
  450.             recur = 1;
  451.             *(ptr-3) = '\0';
  452.         }
  453.         bname = strcpy (salloc(strlen(base)+2), base);
  454.         ptr[1] = scr;
  455.     }
  456.     bl = strlen(bname);
  457.     ename = ++ptr;
  458.     for (; *ptr && *ptr != '/'; ++ptr);
  459.     scr = *ptr;
  460.     *ptr = '\0';
  461.     if (scr) ++ptr;
  462.     tail = ptr;
  463.  
  464.     if ((dp = dopen (bname, &stat)) == NULL || (stat == 0 && *ename)) {
  465.         free (bname);
  466.         free (base);
  467.         free (eav);
  468.         return (NULL);
  469.     }
  470.  
  471.     if (!stat) {                /* eg. 'dir file' */
  472.         char *p,*s;
  473.         for(s = p = bname; *p; ++p) if (*p == '/' || *p == ':') s = p;
  474.         if (s != bname) ++s;
  475.         *s ='\0';
  476.         eav[eac++] = svfile(bname,dp->fib->fib_FileName,dp->fib);
  477.         goto done;
  478.     }
  479.     if (!*ename) ename = "*";    /* eg. dir df0: */
  480.     if (*bname && bname[bl-1] != ':' && bname[bl-1] != '/') { /* dir df0:c */
  481.         bname[bl] = '/';
  482.         bname[++bl] = '\0';
  483.     }
  484.     while ((dnext (dp, &name, &stat)) && !breakcheck()) {
  485.         int match = compare_ok(ename,name,0);
  486.         if (match && (recur || !*tail)) {
  487.             if (eleft < 2) {
  488.                 char **scrav = (char **)salloc(sizeof(char *) * (eac + 10));
  489.                 memmove (scrav, eav, (eac + 1) << 2);
  490.                 free (eav);
  491.                 eav = scrav;
  492.                 eleft = 10;
  493.             }
  494.             eav[eac++] = svfile(bname,name,dp->fib);
  495.             --eleft;
  496.         }
  497.         if ((*tail && match) || recur) {
  498.             int alt_ac;
  499.             char *search, **alt_av, **scrav;
  500.             BPTR lock;
  501.  
  502.             if (stat!=1)           /* expect more dirs, but this not a dir */
  503.                 continue;
  504.             lock = CurrentDir (dp->lock);
  505.             search = salloc(strlen(ename)+strlen(name)+strlen(tail)+6);
  506.             strcpy (search, name);
  507.             strcat (search, "/");
  508.             if (recur) {
  509.                 strcat(search, ".../");
  510.                 strcat(search, ename);
  511.             }
  512.             strcat (search, tail);
  513.             scrav = alt_av = expand (search, &alt_ac);
  514.             free(search);
  515.             CurrentDir (lock);
  516.             if (scrav) {
  517.                 while (*scrav) {
  518.                     int l;
  519.                     if (eleft < 2) {
  520.                         char **scrav = (char **)salloc(sizeof(char *)*(eac+10));
  521.                         memmove ( scrav, eav, (eac + 1) << 2);
  522.                         free (eav);
  523.                         eav = scrav;
  524.                         eleft = 10;
  525.                     }
  526.  
  527.                     l = strlen(*scrav);
  528.                     eav[eac] = salloc(bl+l+1+sizeof(struct file_info));
  529.                     memcpy( eav[eac], *scrav-sizeof(struct file_info),
  530.                     sizeof(struct file_info));
  531.                     eav[eac]+=sizeof(struct file_info);
  532.                     strcpy( eav[eac], bname);
  533.                     strcat( eav[eac], *scrav);
  534.  
  535.                     free (*scrav-sizeof(struct file_info));
  536.                     ++scrav;
  537.                     --eleft, ++eac;
  538.                 }
  539.                 free (alt_av);
  540.             }
  541.         }
  542.     }
  543. done:
  544.     dclose (dp);
  545.     *pac = eac;
  546.     eav[eac] = NULL;
  547.     free (bname);
  548.     free (base);
  549.     if (eac)
  550.         return (eav);
  551.     free (eav);
  552.     return (NULL);
  553. }
  554.  
  555. char *
  556. strupr( char *s )
  557. {
  558.     char *old=s;
  559.     while (*s) *s=toupper(*s), s++;
  560.     return old;
  561. }
  562.  
  563. char *
  564. strlwr( char *s )
  565. {
  566.     char *old=s;
  567.     while (*s) *s=tolower(*s), s++;
  568.     return old;
  569. }
  570.  
  571. /*
  572.  * Compare a wild card name with a normal name
  573.  */
  574.  
  575. int
  576. compare_ok( char *wild, char *name, int casedep)
  577. {
  578.     int queryflag;
  579.     char buf[260], wildbuf[260], *lowname;
  580.  
  581.     if (queryflag=(*wild=='&')) wild++;
  582.     if (*wild=='!') *wild='~';
  583.  
  584.     if (! casedep) {
  585.         strupr(wild);
  586.         strcpy(buf,name);
  587.         strupr(buf);
  588.         lowname=buf;
  589.     } else
  590.         lowname=name;
  591.  
  592.     PreParse(wild, wildbuf);
  593.     if ( ! PatternMatch(wildbuf,lowname)) return 0;
  594.  
  595.     if (queryflag) {
  596.         printf("Select %s%-16s%s [y/n] ? ",o_hilite,name,o_lolite);
  597.         gets(buf);
  598.         return (toupper(*buf)=='Y');
  599.     }
  600.     return 1;
  601. }
  602.  
  603. static char *
  604. svfile( char *s1, char *s2, FIB *fib)
  605. {
  606.     int len=strlen(s1)+strlen(s2)+1;
  607.     char *p = salloc (len+sizeof(struct file_info));
  608.     struct file_info *info;
  609.  
  610.     info=(struct file_info *)p;
  611.     p+=sizeof(struct file_info);
  612.     strcpy(p, s1);
  613.     strcat(p, s2);
  614.     info->flags = fib->fib_Protection;
  615.     if( fib->fib_DirEntryType<0 ) {
  616.         info->size  = fib->fib_Size;
  617.         info->blocks= fib->fib_NumBlocks;
  618.     } else {
  619.         info->size  = -1;
  620.         info->blocks= 0;
  621.     }
  622.     if( fib->fib_Comment[0] )
  623.         info->flags|= 1<<30;
  624.     info->date=fib->fib_Date;
  625.     info->class[0]=1;
  626.     return p;
  627. }
  628.  
  629.  
  630.  
  631. static FILE *out;
  632. static int NumDirs;
  633.  
  634. void
  635. expand_all( char *name, FILE *file )
  636. {
  637.     BPTR lock;
  638.     char path[300];
  639.     FIB  *fib;
  640.  
  641.     out=file;
  642.     printf( " %s\n", name );
  643.     NumDirs=0;
  644.  
  645.     if(fib=AllocMem(sizeof(struct FileInfoBlock),0)) {
  646.         if( lock=Lock( name, ACCESS_READ )) {
  647.             strcpy( path, name );
  648.             exall( lock, path );
  649.             printf( "\n", NumDirs );
  650.         }
  651.         FreeMem(fib,sizeof(struct FileInfoBlock));
  652.     }
  653. }
  654.  
  655. static int
  656. exall( BPTR lock, char *path )
  657. {
  658.     BPTR old, sublock;
  659.     int len;
  660.     struct FileInfoBlock *fib;
  661.  
  662.     old=CurrentDir( lock );
  663.  
  664.     if( !(fib=AllocMem(sizeof(struct FileInfoBlock),0)) )
  665.         return 1;
  666.  
  667.     len=strlen( path );
  668.     Examine( lock, fib );
  669.     while( ExNext( lock, fib ) ) {
  670.         if( fib->fib_DirEntryType==ST_USERDIR )
  671.             if( sublock=Lock( fib->fib_FileName, ACCESS_READ )) {
  672.                 if( !len || path[len-1]==':' )
  673.                     sprintf(path+len,"%s",  fib->fib_FileName);
  674.                 else 
  675.                     sprintf(path+len,"/%s", fib->fib_FileName);
  676.                 fprintf( out, "%s\n", path );
  677.                 fprintf( stdout, " Directories: %d\015", ++NumDirs );
  678.                 fflush ( stdout );
  679.                 if(exall( sublock, path ))
  680.                     break;
  681.                 path[len]=0;
  682.             }
  683.     }
  684.     FreeMem( fib, sizeof(struct FileInfoBlock));
  685.     CurrentDir( old );
  686.     return dobreak();
  687. }
  688.  
  689.  
  690.  
  691. /* Sort routines */
  692.  
  693. static int reverse, factor;
  694.  
  695. int
  696. cmp( FILEINFO *s1, FILEINFO *s2)
  697. {
  698.     return Strcmp( (char *)(s1+1), (char *)(s2+1) );
  699. }
  700.  
  701. int
  702. sizecmp( FILEINFO *s1, FILEINFO *s2)
  703. {
  704.     return s2->size - s1->size;
  705. }
  706.  
  707. int
  708. datecmp( FILEINFO *s1, FILEINFO *s2 )
  709. {
  710.     int r;
  711.     struct DateStamp *d1=&s1->date, *d2=&s2->date;
  712.     if( !(r= d2->ds_Days - d1->ds_Days))
  713.         if( !(r=d2->ds_Minute - d1->ds_Minute ) )
  714.             r=d2->ds_Tick - d1->ds_Tick;
  715.     return r;
  716. }
  717.  
  718.  
  719. int
  720. numcmp( FILEINFO *s1, FILEINFO *s2 )
  721. {
  722.     return atoi((char *)(s1+1))-atoi((char *)(s2+1));
  723. }
  724.  
  725. static void
  726. enterclass( FILEINFO *info )
  727. {
  728.     char *class, *iclass=info->class, *t;
  729.  
  730.     if( *iclass==1 ) {
  731.         if( class=getclass( (char *)(info+1))) {
  732.             strncpy( iclass, class, 11 );
  733.             iclass[11]=0;
  734.             if( t=index(iclass,0xA0))
  735.                 *t=0;
  736.         } else 
  737.             iclass[0]=0;
  738.     }
  739. }
  740.  
  741. int
  742. classcmp( FILEINFO *info1, FILEINFO *info2 )
  743. {
  744.     int r;
  745.  
  746.     enterclass( info1 );
  747.     enterclass( info2 );
  748.  
  749.     r= Strcmp( info1->class, info2->class );
  750.     if( !r ) r=Strcmp((char *)(info1+1),(char *)(info2+1));
  751.     return r;
  752. }
  753.  
  754.  
  755. void
  756. QuickSort( char *av[], int n)
  757. {
  758.     reverse=factor=0;
  759.     DirQuickSort( av, n, cmp, 0, 0 );
  760. }
  761.  
  762. static int (*compare)(FILEINFO *, FILEINFO *);
  763.  
  764. static int
  765. docompare(char *s1,char *s2)
  766. {
  767.     FILEINFO *i1=(FILEINFO *)s1-1, *i2=(FILEINFO *)s2-1;
  768.     int r=(*compare)( i1,i2 );
  769.  
  770.     if( reverse ) r =-r;
  771.     if( factor )  r+= factor*((i2->size<0) - (i1->size<0));
  772.     return r;
  773. }
  774.  
  775. #define QSORT
  776.  
  777. void
  778. DirQuickSort( char *av[], int n, int (*func)(FILEINFO *,FILEINFO *), int rev, int fac)
  779. {
  780.     reverse=rev; compare=func; factor=fac;
  781.  
  782.     quicksort( av, n-1 );
  783. }
  784.  
  785. static void
  786. quicksort( char **av, int n )
  787. {
  788.     char **i, **j, *x, *t;
  789.  
  790.  
  791.     if( n>0 ) {
  792.         i=av; j=av+n; x=av[ n>>1 ];
  793.         do {
  794.             while( docompare(*i,x)<0 ) i++;
  795.             while( docompare(x,*j)<0 ) --j;
  796.             if( i<=j )
  797.                 { t=*i; *i=*j; *j=t; i++; j--; }
  798.         } while( i<=j );
  799.  
  800.         if( j-av < av+n-i ) {
  801.             quicksort( av, j-av  );
  802.             quicksort( i , av+n-i);
  803.         } else {
  804.             quicksort( i , av+n-i);
  805.             quicksort( av, j-av  );
  806.         }
  807.     }
  808. }
  809.  
  810. int
  811. filesize( char *name )
  812. {
  813.     BPTR lock;
  814.     struct FileInfoBlock *fib;
  815.     int  len=0;
  816.  
  817.     if( lock = Lock (name,ACCESS_READ)) {
  818.         if( fib=(struct FileInfoBlock *)AllocMem(sizeof(*fib),MEMF_PUBLIC)) {
  819.             if (Examine (lock, fib))
  820.                 len=fib->fib_Size;
  821.             FreeMem( fib, sizeof(*fib));
  822.         }
  823.         UnLock(lock);
  824.     }
  825.     return len;
  826. }
  827.  
  828.  
  829. #ifndef MIN
  830. #define MIN(x,y) ((x)<(y)?(x):(y))
  831. #endif
  832.  
  833. char **
  834. and( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
  835. {
  836.     char **av=(char **)salloc(MIN(ac1,ac2)*sizeof(char *) ), *str;
  837.     int i, j, k=0;
  838.  
  839.     for( i=0; i<ac1; i++ )
  840.         for( j=0, str=base ? BaseName(av1[i]) : av1[i]; j<ac2; j++ )
  841.             if( !Strcmp(str, base ? BaseName(av2[j]) : av2[j]))
  842.                 av[k++]=av1[i];
  843.     *ac=k;
  844.     return av;
  845. }
  846.  
  847. char **
  848. without( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
  849. {
  850.     char **av=(char **)salloc(ac1*sizeof(char *) ), *str;
  851.     int i, j, k=0;
  852.  
  853.     for( i=0; i<ac1; i++ ) {
  854.         for( j=0, str=base ? BaseName(av1[i]) : av1[i]; j<ac2; j++ )
  855.             if( !Strcmp(str, base ? BaseName(av2[j]) : av2[j] ) )
  856.                 break;
  857.         if( j==ac2 )
  858.             av[k++]=av1[i];
  859.     }
  860.     *ac=k;
  861.     return av;
  862. }
  863.  
  864. char **
  865. or( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
  866. {
  867.     char **av=(char **)salloc((ac1+ac2)*sizeof(char *) ), *str;
  868.     int i, j, k=0;
  869.  
  870.     for( i=0; i<ac1; i++ )
  871.         av[k++]=av1[i];
  872.  
  873.     for( i=0; i<ac2; i++ ) {
  874.         for( j=0, str=base ? BaseName(av2[i]) : av2[i]; j<ac1; j++ )
  875.             if( !Strcmp(str, base ? BaseName(av1[j]) : av1[j] ) )
  876.                 break;
  877.         if( j==ac1 )
  878.             av[k++]=av2[i];
  879.     }
  880.  
  881.     *ac=k;
  882.     return av;
  883. }
  884.  
  885. void
  886. clear_archive_bit( char *name )
  887. {
  888.     struct DPTR *dp;
  889.     int stat;
  890.  
  891.     if(dp = dopen(name,&stat) ) {
  892.         SetProtection( name, dp->fib->fib_Protection&~FIBF_ARCHIVE);
  893.         dclose( dp );
  894.     }
  895. }
  896.  
  897. char *
  898. itoa( int i )
  899. {
  900.     static char buf[20];
  901.     char *pos=buf+19;
  902.     int count=4, flag=0;
  903.  
  904.     if( i<0 )
  905.         flag=1, i=-i;
  906.  
  907.     do {
  908.         if( !--count )
  909.             count=3, *--pos=',';
  910.         *--pos= i%10+'0';
  911.     } while( i/=10 );
  912.  
  913.     if( flag )
  914.         *--pos='-';
  915.  
  916.     return pos;
  917. }
  918.  
  919. char *
  920. itok( int i )
  921. {
  922.     static char buf[16], which;
  923.     char *exp=" KMG", *ptr= buf+(which=8-which);
  924.  
  925.     do
  926.         i=(i+512)/1024, exp++;
  927.     while( i>1024 );
  928.     sprintf( ptr,"%d%c",i,*exp);
  929.  
  930.     return ptr;
  931. }
  932.  
  933. char *
  934. next_a0( char *str )
  935. {
  936.     while( *str && (UBYTE)*str!=0xA0 && *str!='=' && *str!=',') str++;
  937.     if( *str )
  938.         return str+1;
  939.     return NULL;
  940. }
  941.  
  942. static int
  943. gethex( char *str, int l )
  944. {
  945.     int i, val=0, n, c;
  946.  
  947.     if( *str=='.' ) return l==2 ? 256 : 0;
  948.  
  949.     for( i=0; i<l || !l; i++ ) {
  950.         c=*str++;
  951.         if     ( c>='0' && c<='9' ) n=c-'0';
  952.         else if( c>='a' && c<='f' ) n=c-'a'+10;
  953.         else if( c>='A' && c<='F' ) n=c-'A'+10;
  954.         else break;;
  955.         val=16*val+n;
  956.     }
  957.     return (l && i!=l) ? -1 : val;
  958. }
  959.  
  960. strwrdcmp( char *str, char *wrd )
  961. {
  962.     int ret;
  963.     char *ind=index(wrd,0xA0);
  964.  
  965.     if( ind ) *ind=0;
  966.     ret=compare_ok(wrd,str,0);
  967.     if( ind ) *ind=0xA0;
  968.     return !ret;
  969. }
  970.  
  971. int
  972. wrdlen( char *str )
  973. {
  974.     char *old=str;
  975.  
  976.     while( *str && (UBYTE)*str!=0xA0 ) str++;
  977.     return str-old;
  978. }
  979.  
  980. char *
  981. getclass(char *file)
  982. {
  983.     CLASS *cl;
  984.     char *class, *str, *arg, *get, *buf;
  985.     int offs, byte, len, fail;
  986.     BPTR fh;
  987.  
  988.     if( isdir(file) ) return "dir";
  989.  
  990.     if( !(buf=calloc(1024,1))) return NULL;
  991.     if( !(fh=Open(file,MODE_OLDFILE))) return NULL;
  992.     len=Read( fh,buf,1023);
  993.     Close(fh);
  994.  
  995.     for( cl=CRoot; cl; cl=cl->next ) {
  996.         class=cl->name;
  997.         if(!(str=next_a0(cl->name))) continue;
  998.         while( str ) {
  999.             if(!(arg=next_a0( str ))) goto nextclass;
  1000.             switch( *str ) {
  1001.             case 's':
  1002.                 if( (offs=strlen(file)-wrdlen(arg))<0 ) break;
  1003.                 if( !strwrdcmp(file+offs,arg)) goto found;
  1004.                 break;
  1005.             case 'n':
  1006.                 if( !strwrdcmp(BaseName(file),arg) ) goto found;
  1007.                 break;
  1008.             case 'd':
  1009.                 goto found;
  1010.             case 'o':
  1011.                 offs=gethex(arg,0);
  1012.                 if( !(arg=index(arg,','))) goto nextclass;
  1013.                 if( offs>len-10 ) break;
  1014.                 for( get=buf+offs, ++arg; (byte=gethex(arg,2))>=0; arg+=2 )
  1015.                     if( (UBYTE)*get++!=byte && byte!=256 )
  1016.                         goto nexttry;
  1017.                 goto found;
  1018.             case 'c':
  1019.                 if( !len )
  1020.                     goto nexttry;
  1021.                 for( get=buf, fail=0; get<buf+len; get++ )
  1022.                     if( *get<9 || *get>13 && *get<32 || *get>127  )
  1023.                         fail++;
  1024.                 if( fail*8>len )
  1025.                     goto nexttry;
  1026.                 goto found;
  1027.             case 'a':
  1028.                 goto nextclass;
  1029.             default:
  1030.                 goto nextclass;
  1031.             }
  1032. nexttry:    str=next_a0(arg);
  1033.         }
  1034. nextclass: ;
  1035.     }
  1036.  
  1037.     free(buf);
  1038.     return NULL;
  1039.  
  1040. found:
  1041.     free(buf);
  1042.     return (char *)class;
  1043. }
  1044.  
  1045. char *
  1046. getaction( char *class, char *action )
  1047. {
  1048.     CLASS *cl;
  1049.     char *cur, *ind;
  1050.     int len;
  1051.  
  1052.     for( len=0; class[len] && (UBYTE)class[len]!=0xA0; len++ ) ;
  1053.     for( cl=CRoot; cl; cl=cl->next ) {
  1054.         if( strncmp( cur=cl->name,class,len+1 ))
  1055.             continue;
  1056.         do
  1057.             cur=index( cur,0xA0 );
  1058.         while( cur && *++cur!='a');
  1059.  
  1060.         if( cur && (cur=index( ++cur,0xA0 ))) {
  1061.             do {
  1062.                 if( !(ind=index( ++cur,'=' )))
  1063.                     return NULL;
  1064.                 len=ind-cur;
  1065.                 if( len==strlen(action) && !strncmp(action,cur,len))
  1066.                     return ++ind;
  1067.             } while( cur=index(cur,0xA0) );
  1068.         }
  1069.     }
  1070.     return NULL;
  1071. }
  1072.  
  1073. int
  1074. doaction( char *file, char *action, char *args )
  1075. {
  1076.     char *class, *com, *c, *copy, *spc=index(file,' ');
  1077.  
  1078.     if( !(class=getclass(file)))
  1079.         return 10;
  1080.     if( !(com=getaction(class,action)))
  1081.         return 11;
  1082.     if( c=index(com,0xA0) )
  1083.         *c=0;
  1084.     copy=salloc( strlen(com)+strlen(file)+strlen(args)+7 );
  1085.     sprintf(copy,spc?"%s \"%s\" %s":"%s %s %s", com, file, args);
  1086.     execute(copy);
  1087.     free(copy);
  1088.     if( c )
  1089.         *c=0xA0;
  1090.     return 0;
  1091. }
  1092.  
  1093. void *
  1094. salloc( int len )
  1095. {
  1096.     void *ret;
  1097.  
  1098.     if( !len ) len++;
  1099.  
  1100.     if( !(ret=malloc(len))) {
  1101.         fprintf(stderr,"Out of memory -- exiting\n");
  1102.         main_exit( 20 );
  1103.     }
  1104.     return ret;
  1105. }
  1106.  
  1107. void *
  1108. SAllocMem( long size, long req  )
  1109. {
  1110.     void *ret;
  1111.  
  1112.     if( !(ret=AllocMem(size,req))) {
  1113.         fprintf(stderr,"Out of memory -- exiting\n");
  1114.         main_exit( 20 );
  1115.     }
  1116.     return ret;
  1117. }
  1118.